from fastapi import FastAPI, Depends, Request, Form, status
from fastapi.templating import Jinja2Templates
from fastapi.staticfiles import StaticFiles
from fastapi.responses import RedirectResponse, HTMLResponse
from contextlib import asynccontextmanager
from sqlalchemy import create_engine, Column, Integer, String, Float, ForeignKey, DateTime
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, Session, relationship
from datetime import datetime
from pydantic import BaseModel
from typing import List, Optional
from passlib.context import CryptContext
import os

# 数据库配置
SQLALCHEMY_DATABASE_URL = "sqlite:///./shopping.db"
engine = create_engine(
    SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False}
)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()

# 密码哈希配置
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")

# 数据库模型
class User(Base):
    __tablename__ = "users"
    
    id = Column(Integer, primary_key=True, index=True)
    username = Column(String, unique=True, index=True)
    email = Column(String, unique=True, index=True)
    hashed_password = Column(String)
    full_name = Column(String, nullable=True)
    
    orders = relationship("Order", back_populates="owner")
    cart_items = relationship("CartItem", back_populates="owner", cascade="all, delete-orphan")

class Product(Base):
    __tablename__ = "products"
    
    id = Column(Integer, primary_key=True, index=True)
    name = Column(String, index=True)
    description = Column(String, index=True)
    price = Column(Float)
    image_url = Column(String, nullable=True)
    stock = Column(Integer, default=0)
    
    cart_items = relationship("CartItem", back_populates="product")
    order_items = relationship("OrderItem", back_populates="product")

class CartItem(Base):
    __tablename__ = "cart_items"
    
    id = Column(Integer, primary_key=True, index=True)
    quantity = Column(Integer, default=1)
    user_id = Column(Integer, ForeignKey("users.id"))
    product_id = Column(Integer, ForeignKey("products.id"))
    
    owner = relationship("User", back_populates="cart_items")
    product = relationship("Product", back_populates="cart_items")

class Order(Base):
    __tablename__ = "orders"
    
    id = Column(Integer, primary_key=True, index=True)
    total_amount = Column(Float)
    status = Column(String, default="pending")
    created_at = Column(DateTime, default=datetime.utcnow)
    user_id = Column(Integer, ForeignKey("users.id"))
    
    owner = relationship("User", back_populates="orders")
    items = relationship("OrderItem", back_populates="order", cascade="all, delete-orphan")

class OrderItem(Base):
    __tablename__ = "order_items"
    
    id = Column(Integer, primary_key=True, index=True)
    quantity = Column(Integer)
    price = Column(Float)  # 记录购买时的价格
    order_id = Column(Integer, ForeignKey("orders.id"))
    product_id = Column(Integer, ForeignKey("products.id"))
    
    order = relationship("Order", back_populates="items")
    product = relationship("Product", back_populates="order_items")

# 创建数据库表
Base.metadata.create_all(bind=engine)

# 依赖项
def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()

# Pydantic模型
class UserCreate(BaseModel):
    username: str
    email: str
    password: str
    full_name: Optional[str] = None

class UserLogin(BaseModel):
    username: str
    password: str

class ProductCreate(BaseModel):
    name: str
    description: str
    price: float
    image_url: Optional[str] = None
    stock: int

# 初始化FastAPI应用
app = FastAPI(
    title="购物网站",
    description="FastAPI + SQLite 购物网站",
    version="1.0.0",
    debug=False  # 生产环境务必关闭
)

# 配置静态文件和模板
os.makedirs("./frontend/static", exist_ok=True)
app.mount("/static", StaticFiles(directory="./frontend/static"), name="static")
templates = Jinja2Templates(directory="./frontend")

# 辅助函数
def get_password_hash(password):
    return pwd_context.hash(password)

def verify_password(plain_password, hashed_password):
    return pwd_context.verify(plain_password, hashed_password)

def get_user_by_username(db: Session, username: str):
    return db.query(User).filter(User.username == username).first()

def get_user_by_email(db: Session, email: str):
    return db.query(User).filter(User.email == email).first()

def authenticate_user(db: Session, username: str, password: str):
    user = get_user_by_username(db, username)
    if not user:
        return False
    if not verify_password(password, user.hashed_password):
        return False
    return user

# 会话管理 - 简化版，实际应用中应使用更安全的方式
def get_current_user(request: Request, db: Session = Depends(get_db)):
    username = request.cookies.get("username")
    if not username:
        return None
    return get_user_by_username(db, username)

# 路由
@app.get("/", response_class=HTMLResponse)
def home(request: Request, db: Session = Depends(get_db), category: Optional[str] = None):
    products = db.query(Product).all()
    user = get_current_user(request, db)
    return templates.TemplateResponse("index.html", {
        "request": request, 
        "products": products,
        "user": user
    })

@app.get("/product/{product_id}", response_class=HTMLResponse)
def product_detail(request: Request, product_id: int, db: Session = Depends(get_db)):
    product = db.query(Product).filter(Product.id == product_id).first()
    if not product:
        return RedirectResponse(url="/")
    user = get_current_user(request, db)
    return templates.TemplateResponse("product_detail.html", {
        "request": request, 
        "product": product,
        "user": user
    })

@app.get("/register", response_class=HTMLResponse)
def register_page(request: Request):
    return templates.TemplateResponse("register.html", {"request": request})

@app.post("/register", response_class=HTMLResponse)
def register(
    request: Request,
    username: str = Form(...),
    email: str = Form(...),
    password: str = Form(...),
    full_name: str = Form(None),
    db: Session = Depends(get_db)
):
    # 检查用户名和邮箱是否已存在
    if get_user_by_username(db, username):
        return templates.TemplateResponse("register.html", {
            "request": request,
            "error": "Username already exists"
        })
    if get_user_by_email(db, email):
        return templates.TemplateResponse("register.html", {
            "request": request,
            "error": "Email already exists"
        })
    
    # 创建新用户
    hashed_password = get_password_hash(password)
    db_user = User(
        username=username,
        email=email,
        hashed_password=hashed_password,
        full_name=full_name
    )
    db.add(db_user)
    db.commit()
    db.refresh(db_user)
    
    # 注册成功后重定向到登录页
    response = RedirectResponse(url="/login", status_code=status.HTTP_303_SEE_OTHER)
    return response

@app.get("/login", response_class=HTMLResponse)
def login_page(request: Request):
    return templates.TemplateResponse("login.html", {"request": request})

@app.post("/login", response_class=HTMLResponse)
def login(
    request: Request,
    username: str = Form(...),
    password: str = Form(...),
    db: Session = Depends(get_db)
):
    user = authenticate_user(db, username, password)
    if not user:
        return templates.TemplateResponse("login.html", {
            "request": request,
            "error": "Invalid username or password"
        })
    
    # 设置cookie并重定向到主页
    response = RedirectResponse(url="/", status_code=status.HTTP_303_SEE_OTHER)
    response.set_cookie(key="username", value=user.username)
    return response

@app.get("/logout", response_class=HTMLResponse)
def logout():
    response = RedirectResponse(url="/")
    response.delete_cookie(key="username")
    return response

@app.get("/cart", response_class=HTMLResponse)
def cart(request: Request, db: Session = Depends(get_db)):
    user = get_current_user(request, db)
    if not user:
        return RedirectResponse(url="/login")
    
    cart_items = db.query(CartItem).filter(CartItem.user_id == user.id).all()
    total = sum(item.quantity * item.product.price for item in cart_items)
    
    return templates.TemplateResponse("cart.html", {
        "request": request,
        "user": user,
        "cart_items": cart_items,
        "total": total
    })

@app.post("/cart/add/{product_id}", response_class=HTMLResponse)
def add_to_cart(
    request: Request,
    product_id: int,
    quantity: int = Form(1),
    db: Session = Depends(get_db)
):
    user = get_current_user(request, db)
    if not user:
        return RedirectResponse(url="/login")
    
    product = db.query(Product).filter(Product.id == product_id).first()
    if not product:
        return RedirectResponse(url="/")
    
    # 检查库存
    if product.stock < quantity:
        return RedirectResponse(url=f"/product/{product_id}")
    
    # 检查购物车中是否已有该商品
    cart_item = db.query(CartItem).filter(
        CartItem.user_id == user.id,
        CartItem.product_id == product_id
    ).first()
    
    if cart_item:
        cart_item.quantity += quantity
    else:
        cart_item = CartItem(
            user_id=user.id,
            product_id=product_id,
            quantity=quantity
        )
        db.add(cart_item)
    
    db.commit()
    return RedirectResponse(url="/cart")

@app.post("/cart/update/{item_id}", response_class=HTMLResponse)
def update_cart_item(
    request: Request,
    item_id: int,
    quantity: int = Form(...),
    db: Session = Depends(get_db)
):
    user = get_current_user(request, db)
    if not user:
        return RedirectResponse(url="/login")
    
    cart_item = db.query(CartItem).filter(
        CartItem.id == item_id,
        CartItem.user_id == user.id
    ).first()
    
    if cart_item and quantity > 0:
        # 检查库存
        if cart_item.product.stock >= quantity:
            cart_item.quantity = quantity
            db.commit()
    
    return RedirectResponse(url="/cart")

@app.post("/cart/remove/{item_id}", response_class=HTMLResponse)
def remove_from_cart(
    request: Request,
    item_id: int,
    db: Session = Depends(get_db)
):
    user = get_current_user(request, db)
    if not user:
        return RedirectResponse(url="/login")
    
    cart_item = db.query(CartItem).filter(
        CartItem.id == item_id,
        CartItem.user_id == user.id
    ).first()
    
    if cart_item:
        db.delete(cart_item)
        db.commit()
    
    return RedirectResponse(url="/cart")

@app.post("/checkout", response_class=HTMLResponse)
def checkout(request: Request, db: Session = Depends(get_db)):
    user = get_current_user(request, db)
    if not user:
        return RedirectResponse(url="/login")
    
    cart_items = db.query(CartItem).filter(CartItem.user_id == user.id).all()
    if not cart_items:
        return RedirectResponse(url="/cart")
    
    # 计算总金额
    total_amount = sum(item.quantity * item.product.price for item in cart_items)
    
    # 创建订单
    order = Order(
        total_amount=total_amount,
        user_id=user.id,
        status="completed"
    )
    db.add(order)
    db.commit()
    db.refresh(order)
    
    # 创建订单项目并减少库存
    for item in cart_items:
        order_item = OrderItem(
            order_id=order.id,
            product_id=item.product_id,
            quantity=item.quantity,
            price=item.product.price
        )
        db.add(order_item)
        
        # 减少库存
        item.product.stock -= item.quantity
        
        # 从购物车中移除
        db.delete(item)
    
    db.commit()
    
    return RedirectResponse(url=f"/order/{order.id}")

@app.get("/orders", response_class=HTMLResponse)
def list_orders(request: Request, db: Session = Depends(get_db)):
    user = get_current_user(request, db)
    if not user:
        return RedirectResponse(url="/login")
    
    orders = db.query(Order).filter(Order.user_id == user.id).order_by(Order.created_at.desc()).all()
    
    return templates.TemplateResponse("orders.html", {
        "request": request,
        "user": user,
        "orders": orders
    })

@app.get("/order/{order_id}", response_class=HTMLResponse)
def order_detail(request: Request, order_id: int, db: Session = Depends(get_db)):
    user = get_current_user(request, db)
    if not user:
        return RedirectResponse(url="/login")
    
    order = db.query(Order).filter(Order.id == order_id, Order.user_id == user.id).first()
    if not order:
        return RedirectResponse(url="/orders")
    
    return templates.TemplateResponse("order_detail.html", {
        "request": request,
        "user": user,
        "order": order
    })

# 初始化一些测试数据
@app.on_event("startup")
async def startup_event():
    db = SessionLocal()
    # 检查是否已有商品数据
    if db.query(Product).count() == 0:
        # 添加测试商品
        products = [
            Product(
                name="Wireless Headphones",
                description="High quality wireless headphones with noise cancellation",
                price=199.99,
                image_url="/static/products/1.jpg",
                stock=50
            ),
            Product(
                name="Smart Watch",
                description="Fitness tracker with heart rate monitor",
                price=149.99,
                image_url="/static/products/2.jpg",
                stock=30
            ),
            Product(
                name="Bluetooth Speaker",
                description="Portable waterproof speaker",
                price=79.99,
                image_url="/static/products/3.jpg",
                stock=40
            ),
            Product(
                name="Laptop Backpack",
                description="Durable backpack with laptop compartment",
                price=59.99,
                image_url="/static/products/4.jpg",
                stock=25
            ),
            Product(
                name="Wireless Charger",
                description="Fast charging wireless pad",
                price=29.99,
                image_url="/static/products/5.jpg",
                stock=60
            )
        ]
        for product in products:
            db.add(product)
        db.commit()
    db.close()
